using System;
using ClickerClimber.Models;
using ClickerClimber.Managers;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using ClickerClimber.Strategy;
using ClickerClimber.Model;
using System.Collections.Generic;

namespace ClickerClimber
{
    public class Board :IGameObject, IGameObjectDrawable
    {
        // This is a texture we can render.
        Item[,] _cells;
        Item[,] _backgrounds;
        IStrategy _rules;
        Item _clickedItem;
        List<Pair> _patternCells;
        List<Pair> _newItemsToAdd;
        List<Pair> _ItemsToDelete;
        List<Pair> _highlightPattern;

        private bool _thereAreItemsFalling;
        private bool _thereAreBackgroundsFalling;
        private int _topPosition;
        //bool _DeleteBackground = false;

        public void LoadTextures(Microsoft.Xna.Framework.Content.ContentManager content)
        {
            foreach (Item item in _cells)
            {
                if (item != null)
                    item.LoadTextures(content);
            }
            foreach (Item item in _backgrounds)
            {
                if (item != null)
                    item.LoadTextures(content);
            }

        }

        public void Draw(Microsoft.Xna.Framework.Graphics.SpriteBatch batch)
        {
            foreach (Item item in _backgrounds)
            {
                if ((item != null)&&(item.HasBackground))
                {
                    item.Draw(batch);
                }
            } 
            
            foreach (Item item in _cells)
            {
                if ((item != null)&&(item.HasItem))
                {
                    item.Draw(batch);
                }
            }
        }

        public void Initialize()
        {
            _cells = new Item[GameParameters.BOARD_BASE_COLUMNS, GameParameters.BOARD_BASE_ROWS];
            _backgrounds = new Item[GameParameters.BOARD_BASE_COLUMNS, GameParameters.BOARD_BASE_ROWS];
            _rules = new GameStrategy();
            InitializeItems();
            _thereAreItemsFalling = false;
            _thereAreBackgroundsFalling = false;
            _ItemsToDelete = new List<Pair>();
            _highlightPattern = new List<Pair>();
        }

        public bool IsIn(int x, int y, Vector2 pos)
        {
            if (_backgrounds[x, y] != null)
                return _backgrounds[x, y].IsIn(pos);
            else
                return false;
        }

        public Item GetItem(int x, int y)
        {
            return _cells[x, y];
        }

        public Vector2 GetPosition(int x, int y)
        {
            return _backgrounds[x, y].AbsolutePosition;
        }

        public void OnClick(Vector2 pos, List<Beaver> _beaverList)
        {
            _clickedItem = null;
            for (int i = 0; i < GameParameters.BOARD_BASE_ROWS; i++)
            {
                for (int j = 0; j < GameParameters.BOARD_BASE_COLUMNS; j++)
                {
                    if (IsIn(j, i, pos))
                    {
                        _clickedItem = GetItem(j, i);
                    }
                }
            }

            bool bMakeItemsFall = false;

            if (_clickedItem != null && _clickedItem.HasItem)
            {
                bool found = _rules.FindPattern(_cells, _clickedItem, out _patternCells, true);

                if (found && !ThereAreBeaversOnPattern(_patternCells, _beaverList))
                {
                    //if (_cellsToFall.Count >= 3 && _cellsToFall.Count <= 4)
                    {
                        AudioManager.Instance.PlaySound(AudioManager.eSound.clearSmall);
                    }
                    /*else if (_cellsToFall.Count >= 5 && _cellsToFall.Count <= 7)
                    {
                        AudioManager.Instance.PlaySound(AudioManager.eSound.clearMedium);
                    }
                    else if (_cellsToFall.Count >= 8)
                    {
                        AudioManager.Instance.PlaySound(AudioManager.eSound.clearLarge);
                    }*/

                    //Destroy pattern items               
                    foreach (Pair pair in _patternCells)
                    {
                        _cells[pair.Column, pair.Row].HasItem = false;
                    }
                    _newItemsToAdd = this.Refill();
                    bMakeItemsFall = true;
                }
                else
                {
                    _patternCells.Clear();
                }
            }

            
            Refill();

            if(bMakeItemsFall)
                this.MakeItemsFall();

            //_DeleteBackground = true;
        }

        public void AddBackgroundItem(int nbBackgroundItems)
        {
            List<Pair> list = _rules.GetPositionsToFill(nbBackgroundItems, _backgrounds);
            foreach (Pair pair in list)
            {
                this.CreateNewItem(pair.Column, pair.Row);
                this.CreateNewBackground(pair.Column, pair.Row);
                LoadTextures(RendererManager.Instance.Content);
            }

            DataManager.Instance.GameScene.OnClick();
        }

        public Vector2 GetTopBackgroundPosition()
        {
            Pair topBackground = new Pair(0, 0);

            for (int r = 0; r < GameParameters.BOARD_BASE_ROWS; ++r)
            {
                for (int c = 0; c < GameParameters.BOARD_INITIAL_COLUMNS; ++c)
                {
                    if (_backgrounds[c, r] != null && _backgrounds[c,r].HasBackground)
                    {
                        topBackground.Row = r;
                        topBackground.Column = c;
                        _topPosition = r;
                        break;
                    }
                }
            }

            return _backgrounds[topBackground.Column, topBackground.Row].AbsolutePosition;
        }

        public Pair GetTopBackgroundPositionLogic()
        {
            Pair topBackground = new Pair(0, 0);

            for (int r = 0; r < GameParameters.BOARD_BASE_ROWS; ++r)
            {
                for (int c = 0; c < GameParameters.BOARD_INITIAL_COLUMNS; ++c)
                {
                    if (_backgrounds[c, r] != null && _backgrounds[c, r].HasBackground)
                    {
                        topBackground.Row = r;
                        topBackground.Column = c;
                        _topPosition = r;
                        break;
                    }
                }
            }

            return topBackground;
        }

        #region Properties

        public int TopPosition
        {
            get
            {
                return _topPosition+1;
            }
        }

        public IStrategy Rules
        {
            get
            {
                return _rules;
            }
        }

        #endregion Properties

        #region support members

        private void InitializeItems()
        {
           for (int c = 0; c < GameParameters.BOARD_INITIAL_COLUMNS; c++)
           {
               for (int r = 0; r < GameParameters.BOARD_INITIAL_ROWS; r++)
               {
                   this.CreateNewItem(c, r);
                   this.CreateNewBackground(c, r);                   
               }
           }

            /*Fake
           _cells[0, 0].Type = Item.ItemType.BLUE;
           _cells[0, 1].Type = Item.ItemType.RED;
           _cells[0, 2].Type = Item.ItemType.BLUE;

           _cells[1, 0].Type = Item.ItemType.RED;
           _cells[1, 1].Type = Item.ItemType.RED;
           _cells[1, 2].Type = Item.ItemType.BLUE;

           _cells[2, 0].Type = Item.ItemType.BLUE;
           _cells[2, 1].Type = Item.ItemType.BLUE;
           _cells[2, 2].Type = Item.ItemType.BLUE;
            //*/

        }

        private List<Pair> Refill()
        {
            List<Pair> itemsToAdd = new List<Pair>();

            for (int c = 0; c < GameParameters.BOARD_BASE_COLUMNS; c++)
            {
                bool swap = true;

                //bubble method
                while (swap)
                {
                    swap = false;
                    for (int r = GameParameters.BOARD_BASE_ROWS - 1; r >= 0; r--)
                    {
                        if ((_cells[c, r] != null) && ((r>0)&&(_cells[c, r - 1] != null)))
                        {
                            if (r > 0 && _cells[c, r].HasItem && !_cells[c, r - 1].HasItem)// && _backgrounds[c, r-1].HasBackground)
                            {
                                _cells[c, r - 1].HasItem = true;
                                _cells[c, r].HasItem = false;
                                _cells[c, r - 1].Position = _cells[c, r].Position;
                                _cells[c, r - 1].Type = _cells[c, r].Type;
                                _cells[c, r - 1].TextureItem = _cells[c, r].TextureItem;
                                _cells[c, r - 1].TextureItemHightlight = _cells[c, r].TextureItemHightlight;
                                _cells[c, r - 1].Offset = _cells[c, r].Offset;

                                swap = true;
                            }
                        }
                    }
                }
                //refill                
                for (int r = 0; r < GameParameters.BOARD_BASE_ROWS; r++)
                {
                    if ((_cells[c, r] != null) && !_cells[c, r].HasItem && _backgrounds[c, r].HasBackground)
                    {
                        itemsToAdd.Add(new Pair(c, r));
                    }
                }                
            }

            return itemsToAdd;
        }

        private void RefillBackground()
        {
            for (int c = 0; c < GameParameters.BOARD_BASE_COLUMNS; c++)
            {
                bool swap = true;

                //bubble method
                while (swap)
                {
                    swap = false;
                    for (int r = GameParameters.BOARD_BASE_ROWS - 1; r >= 0; r--)
                    {
                        if ((_backgrounds[c, r] != null) && ((r > 0) && (_backgrounds[c, r - 1] != null)))
                        {
                            if (r > 0 && _backgrounds[c, r].HasBackground && !_backgrounds[c, r - 1].HasBackground)
                            {
                                _backgrounds[c, r - 1].HasBackground = true;
                                _backgrounds[c, r].HasBackground = false;
                                _backgrounds[c, r - 1].Position = _backgrounds[c, r].Position;
                                _backgrounds[c, r - 1].TypeBackground = _backgrounds[c, r].TypeBackground;
                                _backgrounds[c, r - 1].TextureItem = _backgrounds[c, r].TextureItem;

                                swap = true;
                            }
                        }
                    }
                }
            }
        }

        private Item CreateNewItem(int c, int r)
        {
            _cells[c, r] = new Item();
            _cells[c, r].CellType = Item.eCellType.ITEM;
            _cells.Initialize();

            Vector2 offset = new Vector2(0, 0);
            Vector2 scale = new Vector2(GameParameters.BOARD_CELL_WIDTH, GameParameters.BOARD_CELL_HEIGHT);
          
            Vector2 pos;

            pos.X = GameParameters.BASE_BOARD_POSITION.X + c * scale.X + offset.X;
            pos.Y = GameParameters.BASE_BOARD_POSITION.Y - (r * scale.Y + offset.Y);
            _cells[c, r].Position = pos;
            _cells[c, r].HasItem = true;
            _cells[c, r].IsVisible = true;
            _cells[c, r].CellPosition = new Pair(c, r);
            _cells[c, r].Type = _rules.GetRandomItemType();
            _cells[c, r].AbsolutePosition = pos;

            return _cells[c, r];
        }

        private Item CreateNewBackground(int c, int r)
        {
            Vector2 offset = new Vector2(0, 0);
            Vector2 scale = new Vector2(GameParameters.BOARD_CELL_WIDTH, GameParameters.BOARD_CELL_HEIGHT);

            Vector2 pos;

            pos.X = GameParameters.BASE_BOARD_POSITION.X + c * scale.X + offset.X;
            pos.Y = GameParameters.BASE_BOARD_POSITION.Y - (r * scale.Y + offset.Y);

            _backgrounds[c, r] = new Item();
            _backgrounds[c, r].CellType = Item.eCellType.BACKGROUND;
            _backgrounds.Initialize();

            _backgrounds[c, r].Position = pos;
            _backgrounds[c, r].HasItem = true;
            _backgrounds[c, r].HasBackground = true;
            _backgrounds[c, r].IsVisible = true;
            _backgrounds[c, r].CellPosition = new Pair(c, r);
            _backgrounds[c, r].TypeBackground = _rules.GetRandomItemBackgroundType();
            _backgrounds[c, r].AbsolutePosition = pos;

            return _backgrounds[c, r];
        }

        private void DeleteBackground(int c, int r)
        {
            _cells[c, r].HasItem = false;
            _backgrounds[c, r].HasBackground = false;
        }

        private bool ThereAreBeaversOnPattern(List<Pair> pattern, List<Beaver> beavers)
        {
            foreach (Pair pair in pattern)
            {
                foreach (Beaver beaver in beavers)
                {
                    if (beaver.IsAlive && beaver.ItemPosition.Column == pair.Column && beaver.ItemPosition.Row == pair.Row)
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        #endregion support members

        #region Update

        public void Update(GameTime gameTime)
        {
            //not used
            throw new NotImplementedException();
        }

        public void Update(GameTime gameTime, List<Beaver> bevers)
        {
            UpdateItems(gameTime, bevers);
            UpdateBackgrounds(gameTime);

            if (!_thereAreItemsFalling)
            {
                int itemsToAdd = this.FillBoardWithNewItems();
                if (itemsToAdd>0)
                {
                    AddBackground(itemsToAdd);
                }

                DeleteItems();

                /*
                if (_DeleteBackground)
                {
                    DeleteBackgrounds(1);
                    _DeleteBackground = false;
                }
                //*/

            }
        }

        private int FillBoardWithNewItems()
        {
            bool res = false;
            if (_newItemsToAdd != null && _newItemsToAdd.Count > 0)
            {
                foreach (Pair pair in _newItemsToAdd)
                {
                    Item item = CreateNewItem(pair.Column, pair.Row);
                    item.LoadTextures(RendererManager.Instance.Content);
                }
                int itemsToAdd = _newItemsToAdd.Count;
                _newItemsToAdd.Clear();
                return itemsToAdd;
            }
            return 0;
        }


        private void UpdateItems(GameTime gameTime, List<Beaver> beavers)
        {
            _thereAreItemsFalling = false;
 
            for (int c = 0; c < GameParameters.BOARD_BASE_COLUMNS; c++)
            {
                for (int r = 0; r < GameParameters.BOARD_BASE_ROWS; r++)
                {
                    if (_cells[c, r] != null)
                    {
                        if (!_cells[c, r].HasItem) continue;

                        _cells[c, r].Update(gameTime);
                        if (!_thereAreItemsFalling)
                        {
                            _thereAreItemsFalling = _cells[c, r].IsFalling;
                        }
                        //Mouse Over
                        if(_cells[c,r].IsIn(InputManager.Instance.GetPosition()) )
                        {
                            //remove last highlight
                            foreach (Pair pair in _highlightPattern)
                            {
                                _cells[pair.Column, pair.Row].Highlight = false;
                            }
                            _highlightPattern.Clear();

                            //search new ones
                            _rules.FindPattern(_cells, _cells[c, r], out _highlightPattern, false);

                            if (_highlightPattern.Count > 2 && !ThereAreBeaversOnPattern(_highlightPattern, beavers))
                            {
                                foreach (Pair pair in _highlightPattern)
                                {
                                    _cells[pair.Column, pair.Row].Highlight = true;
                                }
                            }
                        }
                    }
                }
            }
        }

        private void UpdateBackgrounds(GameTime gameTime)
        {
            _thereAreBackgroundsFalling = false;

            for (int c = 0; c < GameParameters.BOARD_BASE_COLUMNS; c++)
            {
                for (int r = 0; r < GameParameters.BOARD_BASE_ROWS; r++)
                {
                    if (_backgrounds[c, r] != null)
                    {
                        if (!_backgrounds[c, r].HasBackground) continue;

                        _backgrounds[c, r].Update(gameTime);
                        if (!_thereAreBackgroundsFalling)
                        {
                            _thereAreBackgroundsFalling = _backgrounds[c, r].IsFalling;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// </summary>
        /// <param name="gems"></param>
        /// <param name="elapsedTime"></param>
        private void MakeItemsFall()
        {
            for (int c = 0; c < GameParameters.BOARD_BASE_COLUMNS; c++)
            {
                for (int r = 0; r < GameParameters.BOARD_BASE_ROWS; r++)
                {
                    if ((_cells[c, r] != null) && (_cells[c, r].HasItem))
                    {
                        _cells[c, r].ChangeState(Item.ItemState.FALLING);
                    }
                    if ((_backgrounds[c, r] != null) && (_backgrounds[c, r].HasBackground))
                    {
                        _backgrounds[c, r].ChangeState(Item.ItemState.FALLING);
                    }
                }
            }
        }

        private void AddBackground(int backgroundsToAdd)
        {
            switch (backgroundsToAdd)
            {
                case 0:
                case 1:
                case 2:
                    break;
                case 3:
                    AddBackgroundItem(GameParameters.NUM_CREATED_ITEMS_REMOVE3);
                    break;
                case 4:
                    AddBackgroundItem(GameParameters.NUM_CREATED_ITEMS_REMOVE4);
                    break;
                case 5:
                    AddBackgroundItem(GameParameters.NUM_CREATED_ITEMS_REMOVE5);
                    break;
                case 6:
                    AddBackgroundItem(GameParameters.NUM_CREATED_ITEMS_REMOVE6);
                    break;
                case 7:
                    AddBackgroundItem(GameParameters.NUM_CREATED_ITEMS_REMOVE7);
                    break;
                case 8:
                    AddBackgroundItem(GameParameters.NUM_CREATED_ITEMS_REMOVE8);
                    break;
                case 9:
                    AddBackgroundItem(GameParameters.NUM_CREATED_ITEMS_REMOVE9);
                    break;
                case 10:
                    AddBackgroundItem(GameParameters.NUM_CREATED_ITEMS_REMOVE10);
                    break;
                default:
                    AddBackgroundItem(GameParameters.NUM_CREATED_ITEMS_REMOVEMAX);
                    break;
            }
        }

        public void DeleteBackgrounds(int nb)
        {
            Pair pos = GetTopBackgroundPositionLogic();
            List<Pair> list = _rules.GetPositionsToDelete(nb, _backgrounds, pos.Row);
            foreach (Pair pair in list)
            {
                DeleteBackground(pair.Column, pair.Row);
            }
            RefillBackground();
            Refill();
            MakeItemsFall();
        }

        public void AddItemToDelete(Pair pos)
        {
            _ItemsToDelete.Add(pos);
        }

        void DeleteItems()
        {
            bool deleted = false;
            foreach (Pair pair in _ItemsToDelete)
            {
                DeleteBackground(pair.Column, pair.Row);
                deleted = true;
            }
            if (deleted)
            {
                _ItemsToDelete.Clear();
                RefillBackground();
                Refill();
                MakeItemsFall();
            }
        }

        public List<Pair> GetNewBeaverPositions()
        {
            Pair posTop = GetTopBackgroundPositionLogic();
            Pair pos = new Pair(0,0);
            List<Pair> list = _rules.GetPositionsToDelete(10, _backgrounds, posTop.Row);
            //if (list.Count > 0)
            //    pos = list[0];
            //return pos;

            return list;
        }


        public List<Pair> PatternCells
        {
            get
            {
                return _patternCells;
            }
        }

        #endregion Update
    }
}